/*
*******************************************************************************
COPYRIGHT 2010 Atech-Automotive
Source File Name : uds_diag_appl.c
Group            : ATECH
Author           :
Date First Issued:
********************************Documentation**********************************
General Purpose - This file contains the function prototypes for the appl layer.
********************************RevisionHistory********************************
_______________________________________________________________________________
Date : MM/DD/YY                       Release : V1.0
Date : 04/19/2010           the appl layer for diagnoses.

***************************************************************************/

/* #include */
#include "system.h"
#include <string.h>
#include "uds_diag_appl.h"
#include "uds_can_trans.h"

#include "uds_diag_drv.h"
#include "uds_diag_interface.h"
#include "uds_diag_fun.h"
#include "uds_diag_callback.h"
#include "uds_diag_config.h"

#pragma CODE_SEG  OTHER_ROM


/* #define */
#define MAX_STORE_DATA		   (8)      /* 8 * 4 bytes */

#define MODE31_STATUS_BYTE_LENGTH       0x0F


#define DIAG_IF_IN_DIAG_MODE()      (TESTBIT( diag_mode_flags, DIAG_MODE ) != 0)
#define DIAG_IF_NOT_IN_DIAG_MODE()  (TESTBIT( diag_mode_flags, DIAG_MODE ) == 0)

#define DIAG_CHECK_FORBID_BIT()     (TESTBIT( DiagBuffer[ _DATA1 ], 0x80 ) != 0)
     
#define MERGE_U8_TO_U16(high_byte, low_byte) \
    (UINT16)((((UINT16)high_byte) << 8) + low_byte)


/////////////////////////////////////
/* must change these values together with uds_diag_config.h */
#define DEFAULT_MODE        0x02
#define PROGRAM_MODE        0x04
#define ENDOFLINE_MODE      0x08
#define DIAG_MODE           0x80

#define SEC_NONE_MODE       0x00
#define SEC_01_MODE         _SUPP_ACCESS_01
#define SEC_03_MODE         _SUPP_ACCESS_03
#define SEC_05_MODE         _SUPP_ACCESS_05
#define SEC_07_MODE         _SUPP_ACCESS_07
#define SEC_09_MODE         _SUPP_ACCESS_09
#define SEC_MODE_MASK       (SEC_01_MODE|SEC_03_MODE|SEC_05_MODE|SEC_07_MODE|SEC_09_MODE)

/* typedef */
typedef enum
{
    TIMEOUT_5_SECONDS    =  500,    /* using 10ms ticks */
    TIMEOUT_10_SECONDS   =  1000,   /* using 10ms ticks */
    TIMEOUT_30_SECONDS   =  3000,   /* using 10ms ticks */
    TIMEOUT_60_SECONDS   =  6000,   /* using 10ms ticks */
} Uds_TimeOut_E;


/* read DID support */
typedef struct
{
    UINT16 did;     /* The 16-bit DID number */
    UINT8 access_mode;
    UINT8 length;  /* read data length */
    UINT8(*did_read_function_ptr)(UINT8 * pData, UINT8 length);
} Uds_DidReadRecord_S;
/*
** write DID support
*/
typedef struct
{
    UINT16 did;     /* The 16-bit DID number */
    UINT8 access_mode;
    UINT8 length;  /* write data length */
    UINT8(*did_write_function_ptr)(UINT8 * pData, UINT8 length);

} Uds_DidWriteRecord_S;

typedef struct
{
    BOOL app_send_flag;
    BOOL nwm_send_flag;
    BOOL app_rec_flag;
    BOOL nwm_rec_flag;

} Uds_CanCommCtrlSts_S;

typedef struct
{
    UINT8 u8_invalid_counter;
    UINT8 u8_error_counter;
    UINT16 u16_retry_int_counter;
} Uds_AccessRetry_S;

static Uds_AccessRetry_S s_diag_access_retry;

static UINT8 routinue_running_state_array[(NUMER_OF_ROUNTINUE_ID / (UINT8)8) + (UINT8)1 ];

Uds_CanCommCtrlSts_S s_uds_can_comm_ctrl;

/*
** Structure for Io Ctrl
*/
typedef struct
{
    UINT16 local_id;
    UINT8 access_mode;
    UINT8 data_length;
    UINT8(*fun)(Uds_IOCtrl_Cmd_E cmd, UINT8 *p_u8_data);
} Uds_IOCtrlRecord_S;

/*
** Structure for Routine Ctrl
*/
typedef struct
{
    UINT16 routine_id;  /* The 16-bit routine id */
    UINT16 index;
    UINT8  start_access_mode;
    UINT8  start_lenght;        /* start routine option record and status byte lenght */
    UINT8  stop_access_mode;
    UINT8  stop_lenght;         /* stop routine option record and status byte lenght */
    UINT8  result_access_mode;
    UINT8  result_lenght;       /* result routine option record and status byte lenght */
    UINT8(*fun)(RoutineCtrl_Cmd_E cmd, UINT8 const *p_u8_ctrl_opt , UINT8 *p_u8_status_record);

} Uds_RoutineCtrlRecord_S;

typedef enum
{

    MODE_10_SUB_SESS_DEFAULT   = 0x01,
    MODE_10_SUB_SESS_PRAGRAM   = 0x02,
    MODE_10_SUB_SESS_ENDOFLINE = 0x03,

} MODE_10_SubFun_E;

typedef enum
{

    MODE_11_SUB_HARD_RESET = 0x01,
    MODE_11_SUB_IGN_RESET  = 0x02,
    MODE_11_SUB_SOFT_RESET = 0x03,

} MODE_11_SubFun_E;

typedef enum
{
    MODE_19_SUB_NUM_DTC_BY_STATUS_MASK   = 0x01,
    MODE_19_SUB_DTC_BY_STATUS_MASK       = 0x02,
    MODE_19_SUB_SNAPSHOT_BY_DTC_NUM      = 0x04, /* Snap Shot */
    MODE_19_SUB_EXT_DATA_BY_DTC_NUM      = 0x06, /* Ext Record */
    MODE_19_SUB_SUPPORTED_DTC            = 0x0A,

} MODE_19_SubFun_E;

/* read data DID table */
static const Uds_DidReadRecord_S diag_did_read_table_rom[] =
{
    DIAG_DID_READ_TABLE
    {0, 0, 0, NULL_PTR }
};

/* write data DID table */
static const Uds_DidWriteRecord_S diag_did_write_table_rom[] =
{
    DIAG_DID_WRITE_TABLE
    {0, 0, 0, NULL_PTR }
};

/* I/O Control Identifer Table */
static const Uds_IOCtrlRecord_S diag_ioctl_table_rom[] =
{
    DIAG_IOCTL_BY_ID_TABLE
    {0, 0, 0, NULL_PTR}
};

/* Routine Ctrl Table */
static const Uds_RoutineCtrlRecord_S diag_routine_ctrl_table_rom[] =
{
    DIAG_ROUTINE_CTRL_ID_TABLE
    {0, 0, 0, 0, 0, 0, 0, 0, NULL_PTR}
};

/*
** Bit-mapped diagnostic state information.
*/
static UINT8 diag_mode_flags;
static UINT8 diag_sec_levels;
static UINT8 u8_diag_init_time;

static BOOL s_b_request_new_seed = CLEAR;

static BOOL s_b_diag_ecu_reset_flag = CLEAR;

static UINT8 s_u8_diag_ecu_reset_time_cnt = 0x00;

static UINT16 s_u16_test_present_time_out_cnt = 0x00;

static BOOL s_b_write_e2_flag = CLEAR;
static UINT16 s_u16_addr_e2;
static UINT8 s_u8_bytes_e2;
static UINT32 s_u32_buffer_e2[MAX_STORE_DATA];
static UINT32 s_u32_buffer_e2_backup[MAX_STORE_DATA];

static BOOL b_routinePandingFlag = CLEAR;
static Uds_RoutineCtrlRecord_S const *p_s_routinePanding = ((void*)0);

/* global variables */

/* static function prototypes */
static void UdsAppl_SetDefaultMode(void);
static void UdsAppl_DiagnosticInit(void);
static void UdsAppl_ClearFlagOperationTimeOut(void);
static void UdsAppl_ProcessPendingRequest(void);
static BOOL UdsAppl_CheckAccessLevels(UINT8 access_level);

static void UdsAppl_DiagTimeOutIn10ms(void);
static void UdsAppl_DiagClearSessionParameters(void);
static void UdsAppl_ChangeAppNwmTxRxFlag(UINT8 cmd, UINT8 type);
static void UdsAppl_DiagInitReadEE(void);
static void UdsAppl_Handler100ms(void);
static void UdsAppl_Handler1s(void);
static BOOL UdsAppl_CheckService(UINT8 u8_ServiceID, BOOL b_lenghtCheck);
static BOOL UdsAppl_CheckSubFunction(const UdsSubFunction_S *s_subFun, UINT8 u8_subFunId, BOOL b_lenghtCheck);
static UINT8 udsAppl_getCurrentSessionMode(void);


BOOL UdsAppl_isInDiagMode(void)
{
    return (((UINT8)TESTBIT(diag_mode_flags, DIAG_MODE)) != 0) ;
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_Handler1ms
 * Description: 1ms task. Must be called periodically (every 1 ms)
 *
 * Param:   none
 * Return:  none
 * Author:  2015/06/01, hui.pang create this function
 ****************************************************************************/
void UdsAppl_Handler1ms(void)
{
    /* If in diagnostic mode */
    CanTrans_Handler1ms();
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_Handler10ms
 * Description: 10ms task
 *
 * Param:   none
 * Return:  none
 * Author:  2015/06/01, hui.pang create this function
 ****************************************************************************/
void UdsAppl_Handler10ms(void)
{
#define TASK_100MS_CNT (10)
#define TASK_1S_CNT    (100)

    static UINT8 s_u8_100ms_cnt = TASK_100MS_CNT;
    static UINT8 s_u8_1s_cnt = TASK_1S_CNT;

    ///////////////////////////////////////

    /*
    **  Perform diagnostics operations.
    */
    /*  After every 2 continuous failed attempts of security access by the tester, the ECU will be
    locked to attempt for 10 more seconds added to the last locked time, the first locked time is
    10 seconds, the longest time is 1000 seconds, and even ECU power down-up occur during the locked
    time. When ECU power down-up occur, the number of failed attempts and the timer for the locked
    time shall be kept in NVRAM.*/

    ///////////////////////////////////////////
    UdsInterface_Handler10ms();
    UdsAppl_ProcessPendingRequest();
    UdsAppl_DiagTimeOutIn10ms();
    UdsAppl_DiagInitReadEE();
    ///////////////////////////////////////

    if(s_u8_100ms_cnt > 0)
    {
        s_u8_100ms_cnt--;
    }
    else
    {
        s_u8_100ms_cnt = TASK_100MS_CNT;
        UdsAppl_Handler100ms();
    }

    ///////////////////////////////////////

    if(s_u8_1s_cnt > 0)
    {
        s_u8_1s_cnt--;
    }
    else
    {
        s_u8_1s_cnt = TASK_1S_CNT;
        UdsAppl_Handler1s();
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_Handler100ms
 * Description: 100ms task
 *
 * Param:   none
 * Return:  none
 * Author:  2015/06/01, hui.pang create this function
 ****************************************************************************/
static void UdsAppl_Handler100ms(void)
{
    /* If in diagnostic mode, check for exit conditions */
    if(DIAG_IF_IN_DIAG_MODE())
    {
        if(g_u8_diag_neg_resp78_timer > 0)
        {
            if(NEGATIVE_RESP78_3SECOND_SUPPORTED)
            {
                g_u8_diag_neg_resp78_timer--;
            }
        }

        if(g_u16_diag_resp78_timeout_timer > 0)
        {
            g_u16_diag_resp78_timeout_timer--;
        }
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_Handler1s
 * Description: 1s task
 *
 * Param:   none
 * Return:  none
 * Author:  2015/06/01, hui.pang create this function
 ****************************************************************************/
static void UdsAppl_Handler1s(void)
{
    /* If in diagnostic mode, check for exit conditions */

    if(s_diag_access_retry.u16_retry_int_counter > 0)
    {
        s_diag_access_retry.u16_retry_int_counter--;
        if(s_diag_access_retry.u16_retry_int_counter == 0)
        {
            /* clear retry int counter */
            UdsDiag_SecurityAccessWriteAccessCounter((UINT8*)&s_diag_access_retry);
        }
    }

    if(u8_diag_init_time > 0)
    {
        u8_diag_init_time--;
    }
}

/*****************************************************************************/
/**
* Function Name: UdsAppl_DiagTimeOutIn10ms
* Description:
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
static void UdsAppl_DiagTimeOutIn10ms(void)
{    
    /* If in diagnostic mode, check for exit conditions */
    if(DIAG_IF_IN_DIAG_MODE())
    {
        /*
        ** Check the timed operation.
        */
        if(s_u16_test_present_time_out_cnt > 0)   /* Test Present */
        {
            s_u16_test_present_time_out_cnt--;
        }
        else
        {
            /* session timeout */
            /* we only exit diag when not in IO control,
               because IO time is 6s and 60s */
            UdsAppl_ClearFlagOperationTimeOut();
        }
    }

#ifdef MODE_11_SUPPORTED
    if(SET == s_b_diag_ecu_reset_flag)
    {
        if(s_u8_diag_ecu_reset_time_cnt > 0)
        {
            s_u8_diag_ecu_reset_time_cnt--;
        }
        else
        {
            /* EcuReset has started, check if timer expired, if so, reset */
            /* Clear the flag */
            s_b_diag_ecu_reset_flag = CLEAR;

            /* reset */
            UdsCallback_EcuReset();
        }
    }
#endif
}

/*****************************************************************************/
/**
* Function Name: UdsAppl_DiagResetDiagTimer
* Description: This function resets the 5 second diagnostic session timer and
             Lack of Diagnostic Dialog Timer.
             NOTE: It is called whenever a diagnostic frame is either transmitted
             or received in the ECU.
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
void UdsAppl_DiagResetDiagTimer(void)
{
    /*
    ** Reset the diagnostic session timer is in a special diagnostic session.
    */
    if(DIAG_IF_IN_DIAG_MODE())
    {
        s_u16_test_present_time_out_cnt = TIMEOUT_5_SECONDS;
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_Init
 * Description: This is the cold initialization function.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/06/01, hui.pang create this function
 ****************************************************************************/
void UdsAppl_Init(void)
{
    UdsAppl_DiagnosticInit();
    CanTrans_ColdInit();
    UdsInterface_Init();
}

static void UdsAppl_DiagnosticInit(void)
{
    /* Set initial operating state to op mode */
    CLEARBIT(diag_mode_flags, (DIAG_MODE | DEFAULT_MODE | PROGRAM_MODE | ENDOFLINE_MODE));
    CLEARBIT(diag_sec_levels, SEC_MODE_MASK);

    /* set the mode as default mode so we could do some test when power
       on without enter diag */
    SETBIT(diag_mode_flags, DEFAULT_MODE);

    g_uds_diag_status = 0x00; /* clear all g_uds_diag_status flags */

    (void)memset(&routinue_running_state_array[0], 0, sizeof(routinue_running_state_array));

    s_uds_can_comm_ctrl.app_rec_flag  = ON;
    s_uds_can_comm_ctrl.app_send_flag = ON;
    s_uds_can_comm_ctrl.nwm_rec_flag  = ON;
    s_uds_can_comm_ctrl.nwm_send_flag = ON;

    s_b_diag_ecu_reset_flag = CLEAR;

    /* init 10seconds forbit security access */
    u8_diag_init_time = c_u8_0x27_access_diag_init_timer;
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_DiagClearSessionParameters
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2014/11/25, hui.pang create this function
 ****************************************************************************/
void UdsAppl_DiagClearSessionParameters(void)
{
#ifdef MODE_28_SUPPORTED
    /* $28 service parameters */        
    /* after time out, recover the CAN comm */

    s_uds_can_comm_ctrl.app_rec_flag  = ON;
    s_uds_can_comm_ctrl.app_send_flag = ON;
    s_uds_can_comm_ctrl.nwm_rec_flag  = ON;
    s_uds_can_comm_ctrl.nwm_send_flag = ON;

    UdsCallBack_CommCtrl(COMM_APP_SEND, ON);
    UdsCallBack_CommCtrl(COMM_APP_REC,  ON);
    UdsCallBack_CommCtrl(COMM_NWM_SEND, ON);
    UdsCallBack_CommCtrl(COMM_NWM_REC,  ON);
#endif

#ifdef MODE_2F_SUPPORTED
    /* after time out or into default mode, recover the io ctrl state(return to ecu) */
    UdsIOCtrlFun_ExitIoCtrlState();
#endif
    
#ifdef MODE_85_SUPPORTED
    /* $85 service parameters */
    UdsCallBack_StartStopDiag(ON);
#endif
}

/*****************************************************************************/
/**
* Function Name: UdsAppl_SetDefaultMode
* Description:  This function resets parameters on a return to operational mode
             or at init.
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
static void UdsAppl_SetDefaultMode(void)
{
    /* Set the operating state of the ECU to 'default mode' */
    /* clear all diag_mode_flags */
    diag_mode_flags = 0x00;
    diag_sec_levels = 0x00;

    SETBIT(diag_mode_flags, DEFAULT_MODE);   //RQ,20120420, change so we will return to default mode
    UdsAppl_DiagClearSessionParameters();
}

/*****************************************************************************/
/**
* Function Name: UdsAppl_ClearFlagOperationTimeOut
* Description:  This function checks to see if timed operation is timed
               out and abort the operation when timed out.
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
static void UdsAppl_ClearFlagOperationTimeOut(void)
{
    /* If in diagnostic mode, check for exit conditions or for expiration of timer */
    if(DIAG_IF_IN_DIAG_MODE())
    {
        /* Process diagnostic exit routines */
        UdsInterface_ClearResp78Flag();

        /*
        ** Two actions are necessary to release the RX buffer and make it available:
        ** clear PROCESSING_MSG bit and set message length in RX message length to 0.
        */
        CLEARBIT(g_uds_diag_status, PROCESSING_MSG);
        CLEARBIT(g_uds_diag_status, NEGRESP78_PROCESSING);
        CLEARBIT(g_uds_diag_status, NEGRESP78_WAIT_60SEC);
        DiagDataLength = 0;

        (void)memset(&routinue_running_state_array[0], 0, sizeof(routinue_running_state_array));

        UdsCallback_OperationTimeOutClearFlag();

        UdsAppl_SetDefaultMode();  /* Reset RAM parameters and clear timer */
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_ProcessPendingRequest
 * Description: This function is called to Process Pending Request. it's called
 *              periodically by the UdsAppl_Handler10ms function.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/07, hui.pang create this function
 ****************************************************************************/
enum
{
    FSM_UDS_Pending_Idle = 0x00,
    FSM_UDS_Pending_Wait,
};

enum
{
    UDS_Pending_None,
    UDS_Pending_Write_E2,
    UDS_Pending_Start_Routine,
} e_pendingType = UDS_Pending_None;
static UINT8 s_fsm_pending_sts   = FSM_UDS_Pending_Idle;


static void UdsAppl_ProcessPendingRequest(void)
{
    static UINT8 routineStatusByte[MODE31_STATUS_BYTE_LENGTH];
    static UINT16 u16_pending_max_time = 0;
    UINT8 u8_status_byte_length;
    BOOL b_pendingOk = FALSE;
    BOOL b_pendingFault = FALSE;
    ///////////////////////////////////
    
    switch(s_fsm_pending_sts)
    {
        case FSM_UDS_Pending_Idle:
            if(e_pendingType == UDS_Pending_Write_E2)
            {
                if(s_b_write_e2_flag)
                {
                    s_b_write_e2_flag = CLEAR;

                    if(TRUE == UdsCallback_WriteDataToE2(s_u16_addr_e2, s_u32_buffer_e2))
                    {
                        s_fsm_pending_sts = FSM_UDS_Pending_Wait;
                        
                        u16_pending_max_time = 1000;      /* 1000 * 10ms = 10s*/
                    }
                    else
                    {
                        DiagExConditionsNotCorrect_Nrc22(); /* 0x22 */
                        b_pendingFault = TRUE;
                    }
                }
            }
            else if(e_pendingType == UDS_Pending_Start_Routine)
            {
                if(b_routinePandingFlag)
                {
                    b_routinePandingFlag = CLEAR;
                    s_fsm_pending_sts = FSM_UDS_Pending_Wait;
                    
                    u16_pending_max_time = 6000;      /* 6000 * 10ms = 60s*/
                }
            }
            else
            {
                e_pendingType = UDS_Pending_None;
            }
            break;

        case FSM_UDS_Pending_Wait:
            if(e_pendingType == UDS_Pending_Write_E2)
            {                
                if(TRUE == UdsCallBack_GetE2IdleSts(s_u16_addr_e2, s_u32_buffer_e2_backup))
                {
                    if(TRUE == UdsCallBack_GetE2CompareState(s_u16_addr_e2, s_u32_buffer_e2, s_u32_buffer_e2_backup))
                    {
                        UdsInterface_PutResponse(FALSE, 3);
                        b_pendingOk = TRUE;
                    }
                    else
                    {
                        DiagExGeneralProgrammingFailure_Nrc72(); /* 0x72 */
                        b_pendingFault = TRUE;
                    }
                }
                else
                {
                    /* response nrc72 when write e2 time out */
                    if(u16_pending_max_time == 0)
                    {
                        DiagExGeneralProgrammingFailure_Nrc72(); /* 0x72 */
                        b_pendingFault = TRUE;
                    }
                }
            }
            else if(e_pendingType == UDS_Pending_Start_Routine)
            {
                (void)memset(routineStatusByte, 0x00, sizeof(routineStatusByte));
                
                if(p_s_routinePanding == ((void*)0)
                    || p_s_routinePanding->routine_id == 0
                    || p_s_routinePanding->fun == NULL_PTR
                    || u16_pending_max_time == 0)
                {
                    DiagExConditionsNotCorrect_Nrc22(); /* 0x22 */
                    b_pendingFault = TRUE;
                }
                else if(p_s_routinePanding->fun(REQ_ROUTINE_RESULTS,
                                                (UINT8 const *)&DiagBuffer[_DATA4],
                                                routineStatusByte) != FALSE)
                {
                    u8_status_byte_length = p_s_routinePanding->result_lenght&0x0F;
                    if(u8_status_byte_length != 0)
                    {
                        (void)memcpy(&DiagBuffer[_DATA4], routineStatusByte, u8_status_byte_length);
                    }
                    UdsInterface_PutResponse(FALSE, 4+u8_status_byte_length);
                    b_pendingOk = TRUE;
                }
            }
            else
            {
                s_fsm_pending_sts = FSM_UDS_Pending_Idle;
            }
            break;

        default:
            e_pendingType = UDS_Pending_None;
            s_fsm_pending_sts = FSM_UDS_Pending_Idle;
            break;
    }
    
    if(u16_pending_max_time)
    {
        u16_pending_max_time--;
    }

    if(b_pendingOk || b_pendingFault)
    {
        CLEARBIT(g_uds_diag_status, PROCESSING_MSG);
        CLEARBIT(g_uds_diag_status, NEGRESP78_PROCESSING);
        CLEARBIT(g_uds_diag_status, NEGRESP78_WAIT_60SEC);

        e_pendingType = UDS_Pending_None;

        s_fsm_pending_sts = FSM_UDS_Pending_Idle;
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_DiagInitReadEE
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2014/12/12, hui.pang create this function
 ****************************************************************************/
static void UdsAppl_DiagInitReadEE(void)
{
    static BOOL s_b_init_ok_flag = FALSE;
    UINT8 u8_response = 0x00;

    ////////////////////////////////////////////////

    if(TRUE == s_b_init_ok_flag)
    {
        return;
    }

    u8_response = UdsCallBack_ReadE2Init();

    if(TRUE == u8_response)
    {
        s_b_init_ok_flag = TRUE;
        
        /*  After every 2 continuous failed attempts of security access by the tester, the ECU will be
        locked to attempt for 10 more seconds added to the last locked time, the first locked time is
        10 seconds, the longest time is 1000 seconds, and even ECU power down-up occur during the locked
        time. When ECU power down-up occur, the number of failed attempts and the timer for the locked
        time shall be kept in NVRAM.*/

        (void)UdsDiag_SecurityAccessReadAccessCounter((UINT8*)&s_diag_access_retry);
    }
}

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagDiagnosticSessionCtrl_0x10(void)
* Description:   This function processes incoming requests
                (0x10) Diagnostic Session Ctrl service
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_10_SUPPORTED

void UdsAppl_DiagDiagnosticSessionCtrl_0x10(void)
{
    BOOL s_b_enter_bootloader = CLEAR;

    BOOL b_forbid_flag = FALSE;

    //////////////////////////////////////////

    /* check session support as well as length*/
    if(FALSE == UdsAppl_CheckService(ENTRDIAG, TRUE))
    {
        return;
    }

    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x10SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }

    /////////////////////////////////////////
    /*if highest bit is 1 it means we do not need to response- Lele*/
    b_forbid_flag = DIAG_CHECK_FORBID_BIT();

    DiagBuffer[ _DATA1 ] &= 0x7F;

    //////////////////////////////////////

    s_b_request_new_seed = SET;

    if(DiagBuffer[ _DATA1 ] == MODE_10_SUB_SESS_ENDOFLINE)   //10 03
    {
        CLEARBIT( diag_mode_flags, ( DEFAULT_MODE | PROGRAM_MODE | ENDOFLINE_MODE | DIAG_MODE) );
        CLEARBIT( diag_sec_levels, SEC_MODE_MASK );
        SETBIT( diag_mode_flags, ENDOFLINE_MODE | DIAG_MODE );
    }
    else if(DiagBuffer[ _DATA1 ] == MODE_10_SUB_SESS_DEFAULT)
    {
        UdsAppl_ClearFlagOperationTimeOut();
        CLEARBIT( diag_mode_flags, ( DEFAULT_MODE | PROGRAM_MODE | ENDOFLINE_MODE | DIAG_MODE) );
        CLEARBIT( diag_sec_levels, SEC_MODE_MASK );
        SETBIT( diag_mode_flags, DEFAULT_MODE );
    }
    else if(DiagBuffer[ _DATA1 ] == MODE_10_SUB_SESS_PRAGRAM)    //RQ, 20130912, add for bootloader, we can only enter into program mode from end of line
    {
        /*0x92 :The current voltage is above a maximum threshold
         for programming when request a programming session*/
        if(UdsDiag_DiagnosticSessionCtrlVoltageTooHigh() == TRUE)
        {
            DiagExSerivcenotSupport_voltageTooHigh_Nrc92();
            return ;
        }
        /*0x93 :The current voltage is below a minimum threshold
           for programming when request a programming session.*/
        else if(UdsDiag_DiagnosticSessionCtrlVoltageTooLow() == TRUE)
        {
            DiagExSerivcenotSupport_voltageTooLow_Nrc93();
            return ;
        }
        else
        {
        }
        /* at here we can config whether support from 01 to 02 */
        if((diag_mode_flags & ENDOFLINE_MODE)||(c_b_0x10_support_default_to_pragram))
        {
            if(UdsDiag_DiagnosticSessionCtrlProgramCondition() == FALSE)
            {
                DiagExConditionsNotCorrect_Nrc22();
                s_b_enter_bootloader = CLEAR;
                return;
            }
            else
            {
                CLEARBIT( diag_mode_flags, ( DEFAULT_MODE | PROGRAM_MODE | ENDOFLINE_MODE | DIAG_MODE) );
                CLEARBIT( diag_sec_levels, SEC_MODE_MASK );
                SETBIT( diag_mode_flags, PROGRAM_MODE | DIAG_MODE );
                /*set flag and reset will be done later*/
                s_b_enter_bootloader = SET;
            }
        }
        else
        {
            DiagExConditionsNotCorrect_Nrc22();
            return;
        }
    }
    
    UdsAppl_DiagResetDiagTimer();

    /*reply with timing parameters */
    DiagBuffer[_DATA2] = (UINT8)(c_u16_p2can_server_max >> 8);
    DiagBuffer[_DATA3] = (UINT8)(c_u16_p2can_server_max >> 0); /* 50,  P2 SERVER 50MS IN 1MS */
    DiagBuffer[_DATA4] = (UINT8)(c_u16_p2xcan_server_max >> 8);
    DiagBuffer[_DATA5] = (UINT8)(c_u16_p2xcan_server_max >> 0); /* 500, P2* SERVER 5S, in 10ms */

    UdsInterface_PutResponse(b_forbid_flag, 6); 	// RQ, 20131028, should not response, // RQ, 20120730, 0XFF means we do not need to send back any msg,only used to clear some flag

    /* we write a flag here, then reset the MCU to enter into bootloader,
       this flag will keep and checked by bootloader */
    if(SET == s_b_enter_bootloader)
    {
        s_b_enter_bootloader = CLEAR;
        UdsCallback_JumpBootload();
    }
}
#endif /* MODE_10_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagECUReset_0x11(void)
* Description:  This function processes incoming requests
                (0x11) ECU reset
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_11_SUPPORTED


void UdsAppl_DiagECUReset_0x11(void)
{
    BOOL b_forbid_flag = 0x00;

    /////////////////////////////////////////////////////////

    /* check session support as well as length*/
    if(FALSE == UdsAppl_CheckService(ECURESET, TRUE))
    {
        return;
    }

    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x11SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }

    //////////////////////////////////////////////////////////

    b_forbid_flag = DIAG_CHECK_FORBID_BIT();

    DiagBuffer[ _DATA1 ] &= 0x7F;

    //////////////////////////////////////////////////////////

    if(UdsDiag_ResetEcuCondition() == FALSE)
    {
        DiagExConditionsNotCorrect_Nrc22();
        return;
    }
    else
    {
        UdsInterface_PutResponse(b_forbid_flag, 0);
        /* Start timer to reset the ECU */
        s_u8_diag_ecu_reset_time_cnt = c_u8_0x11_ecu_reset_time;

        /* set reset flag,Indicate that timer has started */
        s_b_diag_ecu_reset_flag = SET;
    }

}
#endif  /* MODE_11_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagClearDiagnosticInformation_0x14(void)
* Description:  This function processes incoming requests
                (0x14)Clear Diagnostic Information
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_14_SUPPORTED

void UdsAppl_DiagClearDiagnosticInformation_0x14(void)
{
    UINT8 u8_dtcIndex;

    /* check session support as well as length*/
    if(FALSE == UdsAppl_CheckService(CLRDTCRQ, TRUE))
    {
        return;
    }
    
    /*
    ** Verify request message is valid.
    */
    if(DiagBuffer[ _DATA1 ] == 0xFF
        && DiagBuffer[ _DATA2 ] == 0xFF
        && DiagBuffer[ _DATA3 ] == 0xFF)
    {
        (void)UdsCallBack_ClearAllDTCs();
        UdsInterface_PutResponse(FALSE, 1);
        return;
    }
    else
    {
        if(c_b_0x14_diag_support_clear_single_dtc)
        {
            u8_dtcIndex = UdsCallBack_GetDtcIndex(DiagBuffer[ _DATA1 ],
                                                    DiagBuffer[ _DATA2 ],
                                                    DiagBuffer[ _DATA3 ]);

            if(u8_dtcIndex >= UdsDiag_GetMaxNumberOfDTC())
            {
                if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
                {
                    /* 0x31 - "group Of DTC" is wrong.Only 0xFFFFFF(all groups) is supported. */
                    DiagExRequestOutofRange_Nrc31();
                }
                else
                {
                    UdsInterface_QuitWithoutSendNegativeResponse();
                }
                return;
            }
            else
            {
                (void)UdsCallBack_ClearSingleDTC(u8_dtcIndex);
                UdsInterface_PutResponse(FALSE, 1);
            }
        }
        else
        {
            if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
            {
                /* 0x31 - "group Of DTC" is wrong.Only 0xFFFFFF(all groups) is supported. */
                DiagExRequestOutofRange_Nrc31();
            }
            else
            {
                UdsInterface_QuitWithoutSendNegativeResponse();
            }
            return;
        }
    }
}
#endif  /* MODE_14_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagReadDTCInformation_0x19(void)
* Description:  This function processes incoming requests
                (0x19) Read Status of Diagnostic Trouble Code
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_19_SUPPORTED

void UdsAppl_DiagReadDTCInformation_0x19(void)
{
#define ISO15031_FORMAT   (0x00U)
#define ISO14229_FORMAT   (0x01U)

    UINT8 *p_u8_data;

    UINT16 u16_bytes_to_send = 0;
    UINT16 u16_dtc_index = 0x00;
    UINT16 u16_dtc_count = 0x00;
    UINT8  u8_sts_mask = 0x00;
    DTC_Data_S dtc_code;


    if(FALSE == UdsAppl_CheckService(DTCINFO, TRUE))
    {
        return;
    }

    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x19SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }

    switch(DiagBuffer[_DATA1])
    {
            /* Read the number of DTCs by status mask */
        case MODE_19_SUB_NUM_DTC_BY_STATUS_MASK:  //19 01

            if(DiagDataLength != 3)
            {
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }

            u8_sts_mask = DiagBuffer[_DATA2] & c_u8_0x19_dtc_supported_mask;

            for(u16_dtc_index = 0; u16_dtc_index < UdsDiag_GetMaxNumberOfDTC(); u16_dtc_index++)
            {
                dtc_code = UdsCallBack_GetDtcListAndSts(u16_dtc_index);
            
                if(u8_sts_mask & dtc_code.status)
                {
                    u16_dtc_count++;
                }
            }

            DiagBuffer[_DATA2] = c_u8_0x19_dtc_supported_mask;
            DiagBuffer[_DATA3] = ISO14229_FORMAT;
            DiagBuffer[_DATA4] = (UINT8)(u16_dtc_count>>8);
            DiagBuffer[_DATA5] = (UINT8)(u16_dtc_count);

            UdsInterface_PutResponse(FALSE, 6);
            break;

            /* repotr DTCs by status mask */
        case  MODE_19_SUB_DTC_BY_STATUS_MASK:  //19 02

            if(DiagDataLength != 3)
            {
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }

            u8_sts_mask = DiagBuffer[_DATA2] & c_u8_0x19_dtc_supported_mask;
            p_u8_data = &DiagBuffer[_DATA3];

            if(0x00 != u8_sts_mask)   /* valid bit setting check, BIT3 or BIT0 must be 1 */
            {
                /* set the number of bytes to be transmited */
                DiagBuffer[_DATA2] = c_u8_0x19_dtc_supported_mask;
                
                for(u16_dtc_index = 0; u16_dtc_index < UdsDiag_GetMaxNumberOfDTC(); u16_dtc_index++)
                {
                    dtc_code = UdsCallBack_GetDtcListAndSts(u16_dtc_index);

                    if(u8_sts_mask & dtc_code.status)
                    {
                        p_u8_data[u16_bytes_to_send]     = dtc_code.high;
                        p_u8_data[u16_bytes_to_send + 1] = dtc_code.middle;
                        p_u8_data[u16_bytes_to_send + 2] = dtc_code.low;
                        p_u8_data[u16_bytes_to_send + 3] = dtc_code.status & c_u8_0x19_dtc_supported_mask;
                        u16_bytes_to_send += 4;
                    }
                    
                    if(u16_bytes_to_send >= RX_MAX_TP_BYTES-3-4)
                    {
                        break;      //trans buff overflow!!!
                    }
                }

                UdsInterface_PutResponse(FALSE, u16_bytes_to_send + 3);
            }
            else
            {
                //do nothing
                DiagExRequestOutofRange_Nrc31();
                return;
            }
            break;

        case  MODE_19_SUB_SNAPSHOT_BY_DTC_NUM: //19 04

            if(DiagDataLength != 6)
            {
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }
            u16_dtc_index = UdsCallBack_GetDtcIndex(DiagBuffer[ _DATA2 ],
                                                   DiagBuffer[ _DATA3 ],
                                                   DiagBuffer[ _DATA4 ]);
            if(u16_dtc_index >= UdsDiag_GetMaxNumberOfDTC())
            {
                DiagExRequestOutofRange_Nrc31();
                return;
            }
            p_u8_data = &DiagBuffer[_DATA2];
            dtc_code = UdsCallBack_GetDtcListAndSts(u16_dtc_index);

            p_u8_data[0] = dtc_code.high;
            p_u8_data[1] = dtc_code.middle;
            p_u8_data[2] = dtc_code.low;
            p_u8_data[3] = dtc_code.status & c_u8_0x19_dtc_supported_mask;

            u16_bytes_to_send = 4;

            u16_bytes_to_send += UdsCallBack_GetSnapshotDtcRecodeSts(u16_dtc_index, &p_u8_data[u16_bytes_to_send]);
            
            UdsInterface_PutResponse(FALSE, 2 + u16_bytes_to_send);
            break;

        case  MODE_19_SUB_EXT_DATA_BY_DTC_NUM: /* 19  06 */

            if(DiagDataLength != 6)
            {
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }

            u16_dtc_index = UdsCallBack_GetDtcIndex(DiagBuffer[ _DATA2 ],
                                                   DiagBuffer[ _DATA3 ],
                                                   DiagBuffer[ _DATA4 ]);
            
            if(u16_dtc_index >= UdsDiag_GetMaxNumberOfDTC())
            {
                DiagExRequestOutofRange_Nrc31();
                return;
            }

            DiagBuffer[_DATA5] = 0x01;
            p_u8_data = &DiagBuffer[_DATA6];

            u16_bytes_to_send = UdsCallBack_GetExtendDataDtcRecode(u16_dtc_index, &p_u8_data[u16_bytes_to_send]);

            UdsInterface_PutResponse(FALSE, 6 + u16_bytes_to_send);
            break;

        case  MODE_19_SUB_SUPPORTED_DTC: /* 19 0A */

            if(DiagDataLength != 2)
            {
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }
            DiagBuffer[_DATA2] = c_u8_0x19_dtc_supported_mask;
            p_u8_data = &DiagBuffer[_DATA3];

            for(u16_dtc_index = 0; u16_dtc_index < UdsDiag_GetMaxNumberOfDTC(); u16_dtc_index++)
            {
                dtc_code = UdsCallBack_GetDtcListAndSts(u16_dtc_index);

                p_u8_data[u16_bytes_to_send]     = dtc_code.high;
                p_u8_data[u16_bytes_to_send + 1] = dtc_code.middle;
                p_u8_data[u16_bytes_to_send + 2] = dtc_code.low;
                p_u8_data[u16_bytes_to_send + 3] = dtc_code.status & c_u8_0x19_dtc_supported_mask;
                u16_bytes_to_send += 4;
                    
                if(u16_bytes_to_send >= RX_MAX_TP_BYTES-3-4)
                {
                    break;      //trans buff overflow!!!
                }
            }

            /* in tp layer, place the left dtc data from the
            ** beginning(data2) of the buffer.
            */

            UdsInterface_PutResponse(FALSE, u16_bytes_to_send + 3);

            break;

        default:
            break;
    }
}
#endif  /* MODE_19_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagReadDataByIdentifier_0x22(void)
* Description: This function processes incoming requests
                (0x22)read data by identifier
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_22_SUPPORTED

void UdsAppl_DiagReadDataByIdentifier_0x22(void)
{
    const Uds_DidReadRecord_S * did_table_ptr;
    UINT16 u16_did = 0;
    UINT8 response = FALSE;

    /////////////////////////////////////////////////////////

    /* check session support as well as length*/
    if(FALSE == UdsAppl_CheckService(RDBYID, TRUE))
    {
        return;
    }

    did_table_ptr = diag_did_read_table_rom;

    u16_did = MERGE_U8_TO_U16(DiagBuffer[_DATA1],
                              DiagBuffer[_DATA2]);

    while(did_table_ptr->did != 0)
    {
        if(did_table_ptr->did == u16_did)
        {
            if(FALSE == UdsAppl_CheckAccessLevels(did_table_ptr->access_mode))
            {
                DiagExsecurityAccessDenied_Nrc33();
                return ;
            }

            (void)memset(&DiagBuffer[_DATA3], 0x00, did_table_ptr->length);

            response = did_table_ptr->did_read_function_ptr(&DiagBuffer[_DATA3],
                       did_table_ptr->length);

            if(response == TRUE)
            {
                UdsInterface_PutResponse(FALSE, did_table_ptr->length + 3);
            }
            else
            {
                DiagExConditionsNotCorrect_Nrc22();
            }
            return;
        }
        ++did_table_ptr;
    }

    DiagExRequestOutofRange_Nrc31();
    return;
}
#endif  /* MODE_22_SUPPORTED */

/****************************************************************************/
/**
 * Function Name: UdsAppl_DiagSecurityAccess_0x27
 * Description: This function processes incoming requests
 *              (0x27) security access service
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/08, hui.pang create this function
 ****************************************************************************/
#ifdef MODE_27_SUPPORTED

void UdsAppl_DiagSecurityAccess_0x27(void)
{
    static BOOL b_already_request_seed = CLEAR;

    static UINT32 u32_seed;
    static UINT32 u32_key;

    static UINT8 u8_access_seed;

    /*  After every 2 continuous failed attempts of security access by the tester, the ECU will be
    locked to attempt for 10 more seconds added to the last locked time, the first locked time is
    10 seconds, the longest time is 1000 seconds, and even ECU power down-up occur during the locked
    time. When ECU power down-up occur, the number of failed attempts and the timer for the locked
    time shall be kept in NVRAM.*/

    /* check session support as well as length*/
    if(FALSE == UdsAppl_CheckService(SECACCESS, TRUE))
    {
        return;
    }

    if(FALSE == UdsAppl_CheckSubFunction(c_s_uds0x27SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }
    
    if(u8_diag_init_time > 0
        || s_diag_access_retry.u16_retry_int_counter > 0)
    {
        /* 0x37 - Send if the delay timer is active and a request is transmitted */
        DiagExRequiredTimeDelayNotExpired_Nrc37();
        return;
    }

    /****************** SecrityAccessRequest#1 ******************/
    if( DiagBuffer[ _DATA1 ] & BIT0 )
    {
        /* RequestSeed */
        u8_access_seed = DiagBuffer[_DATA1];

        if((diag_sec_levels == SEC_01_MODE && u8_access_seed == 0x01)
                || (diag_sec_levels == SEC_03_MODE && u8_access_seed == 0x03)
                || (diag_sec_levels == SEC_05_MODE && u8_access_seed == 0x05)
                || (diag_sec_levels == SEC_07_MODE && u8_access_seed == 0x07)
                || (diag_sec_levels == SEC_09_MODE && u8_access_seed == 0x09)
          )
        {
            /* 0x0000 - indicates server is not locked */
            if(FALSE == s_b_request_new_seed)
            {
                DiagBuffer[ _DATA2 ] = 0x00; /* seed #1 */
                DiagBuffer[ _DATA3 ] = 0x00; /* seed #2 */
                DiagBuffer[ _DATA4 ] = 0x00; /* seed #3 */
                DiagBuffer[ _DATA5 ] = 0x00; /* seed #4 */
                UdsInterface_PutResponse(FALSE, 2+c_u8_0x27_access_seed_lenght);
                return;
            }
        }

        s_b_request_new_seed = CLEAR; /* RQ, add 20131028, to control whether we need to send seed */
        u32_seed += UdsCallback_GetRandomValueU32();
        if(u32_seed == 0)
        {
            u32_seed++;
        }

        if(c_u8_0x27_access_seed_lenght == 4)
        {
            DiagBuffer[ _DATA2 ] = ((u32_seed >> 24) & 0xFF);     /* seed #1 */
            DiagBuffer[ _DATA3 ] = ((u32_seed >> 16) & 0xFF);     /* seed #2 */
            DiagBuffer[ _DATA4 ] = ((u32_seed >>  8) & 0xFF);     /* seed #3 */
            DiagBuffer[ _DATA5 ] = ((u32_seed >>  0) & 0xFF);     /* seed #4 */
        }
        else
        {
            u32_seed &= 0x0000FFFF;
            DiagBuffer[ _DATA2 ] = ((u32_seed >> 8) & 0xFF);     /* seed #1 */
            DiagBuffer[ _DATA3 ] = ((u32_seed >> 0) & 0xFF);     /* seed #2 */
        }

        b_already_request_seed = SET;

        u32_key = UdsCallback_CalcKey(u32_seed , u8_access_seed);

        UdsInterface_PutResponse(FALSE, 2+c_u8_0x27_access_seed_lenght);
        return ;
    }
    /****************** SecrityAccessRequest#2 ******************/
    else
    {
        /* check key */ 
        if(b_already_request_seed == CLEAR
            || u8_access_seed+1 != DiagBuffer[ _DATA1 ])
        {
            /* 0x24 - request seed firstly,then cal the key */
            DiagExRequestSequenceError_Nrc24();
            return;
        }
        else
        {
            b_already_request_seed = CLEAR;
        }

        if(((c_u8_0x27_access_seed_lenght == 4)
                && (DiagBuffer[ _DATA2 ] == ((u32_key >> 24) & 0xFF))
                && (DiagBuffer[ _DATA3 ] == ((u32_key >> 16) & 0xFF))
                && (DiagBuffer[ _DATA4 ] == ((u32_key >>  8) & 0xFF))
                && (DiagBuffer[ _DATA5 ] == ((u32_key >>  0) & 0xFF)))
            || ((c_u8_0x27_access_seed_lenght == 2)
                && (MERGE_U8_TO_U16(DiagBuffer[ _DATA2 ], DiagBuffer[ _DATA3 ]) == (u32_key & 0xFFFF)))
          )
        {
            if(u8_access_seed == 0x01)
            {
                CLEARBIT(diag_sec_levels, SEC_MODE_MASK);
                SETBIT(diag_sec_levels, SEC_01_MODE);
            }
            else if(u8_access_seed == 0x03)
            {
                CLEARBIT(diag_sec_levels, SEC_MODE_MASK);
                SETBIT(diag_sec_levels, SEC_03_MODE);
            }
            else if(u8_access_seed == 0x05)
            {
                CLEARBIT(diag_sec_levels, SEC_MODE_MASK);
                SETBIT(diag_sec_levels, SEC_05_MODE);
            }
            else if(u8_access_seed == 0x07)
            {
                CLEARBIT(diag_sec_levels, SEC_MODE_MASK);
                SETBIT(diag_sec_levels, SEC_07_MODE);
            }
            else if(u8_access_seed == 0x09)
            {
                CLEARBIT(diag_sec_levels, SEC_MODE_MASK);
                SETBIT(diag_sec_levels, SEC_09_MODE);
            }

            UdsInterface_PutResponse(FALSE, 2);
            /*Once a successful attempt happen, the locked timer and the number of failed attempts
              shall be reset.*/
            s_diag_access_retry.u8_invalid_counter = 0;
            s_diag_access_retry.u8_error_counter = 0;
            s_diag_access_retry.u16_retry_int_counter = 0;
        }
        else
        {
            s_diag_access_retry.u8_invalid_counter++;
        }
    }
    
    if(s_diag_access_retry.u8_invalid_counter >= c_u8_access_invalid_attempt_counter)
    {
        s_diag_access_retry.u8_invalid_counter = 0;
        if(s_diag_access_retry.u8_error_counter < 0xFF)
        {
            s_diag_access_retry.u8_error_counter++;
        }
        s_diag_access_retry.u16_retry_int_counter = (UINT16)s_diag_access_retry.u8_error_counter * c_u16_0x27_access_retry_time_interval;
        if(s_diag_access_retry.u16_retry_int_counter > c_u16_0x27_access_retry_time_interval_max)
        {
            s_diag_access_retry.u16_retry_int_counter = c_u16_0x27_access_retry_time_interval_max;
        }
    }
    
    if(s_diag_access_retry.u8_invalid_counter > 0)
    {
        DiagExInvalidkey_Nrc35(); /* one more chance */
    }
    else if(s_diag_access_retry.u8_error_counter > 0)
    {
        DiagExceednumberOfAttempts_Nrc36();
    }

    /* When ECU power down-up occur, the number of failed attempts and the timer for the locked
    time shall be kept in NVRAM.*/

    UdsDiag_SecurityAccessWriteAccessCounter((UINT8*)&s_diag_access_retry);
}
#endif /* MODE_27_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagCommCtrl_0x28(void)
* Description:  This function processes incoming requests
                (0x28) comm comtrol
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_28_SUPPORTED

#define MODE_28_SUB_COMM_ENABLE_RX_TX         (0x00)
#define MODE_28_SUB_COMM_ENABLE_RX_DISABLE_TX (0x01)
#define MODE_28_SUB_COMM_ENABLE_TX_DISABLE_RX (0x02)
#define MODE_28_SUB_COMM_DISABLE_RX_TX        (0x03)

#define MODE_28_CTRL_TYPE_NONE         (0x00)
#define MODE_28_CTRL_TYPE_APP          (0x01)
#define MODE_28_CTRL_TYPE_NWM          (0x02)
#define MODE_28_CTRL_TYPE_APP_AND_NWM  (0x03)

void UdsAppl_DiagCommCtrl_0x28(void)
{
    BOOL b_forbid_flag = 0x00;

    /////////////////////////////////////////////////////////

    if(FALSE == UdsAppl_CheckService(COMMCTRL, TRUE))
    {
        return;
    }
    
    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x28SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }


    b_forbid_flag = DIAG_CHECK_FORBID_BIT(); /* Check Forbid */

    DiagBuffer[ _DATA1 ] &= 0x7F;


	if(DiagBuffer[ _DATA1 ] == MODE_28_SUB_COMM_DISABLE_RX_TX
			&& (UdsDiag_CommunicationControlDisableRxTxCondition() == FALSE)
	  )
	{
		DiagExConditionsNotCorrect_Nrc22();
		return;
	}

	if((DiagBuffer[ _DATA2 ] == MODE_28_CTRL_TYPE_APP)
			|| (DiagBuffer[ _DATA2 ] == MODE_28_CTRL_TYPE_NWM)
			|| (DiagBuffer[ _DATA2 ] == MODE_28_CTRL_TYPE_APP_AND_NWM)
	  )
	{
		/* set control flag */
		UdsAppl_ChangeAppNwmTxRxFlag(DiagBuffer[_DATA1],
									DiagBuffer[_DATA2]);
		UdsInterface_PutResponse(b_forbid_flag, 2);
	}
	else
	{
        if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
        {
            /* 0x31 - "group Of DTC" is wrong.Only 0xFFFFFF(all groups) is supported. */
            DiagExRequestOutofRange_Nrc31();
        }
        else
        {
            UdsInterface_QuitWithoutSendNegativeResponse();
        }
		return;
	}
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_ChangeAppNwmTxRxFlag
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2014/07/14, hui.pang create this function
 ****************************************************************************/
static void UdsAppl_ChangeAppNwmTxRxFlag(UINT8 cmd, UINT8 type)
{
    if(MODE_28_CTRL_TYPE_APP == type)
    {
        if(MODE_28_SUB_COMM_ENABLE_RX_TX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = ON;
            s_uds_can_comm_ctrl.app_send_flag  = ON;
        }
        else if(MODE_28_SUB_COMM_ENABLE_RX_DISABLE_TX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = ON;
            s_uds_can_comm_ctrl.app_send_flag  = OFF;
        }
        else if(MODE_28_SUB_COMM_ENABLE_TX_DISABLE_RX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = OFF;
            s_uds_can_comm_ctrl.app_send_flag  = ON;
        }
        else if(MODE_28_SUB_COMM_DISABLE_RX_TX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = OFF;
            s_uds_can_comm_ctrl.app_send_flag  = OFF;
        }
        else
        {
            /* do nothing */
        }
    }
    else if(MODE_28_CTRL_TYPE_NWM == type)
    {
        if(MODE_28_SUB_COMM_ENABLE_RX_TX == cmd)
        {
            s_uds_can_comm_ctrl.nwm_rec_flag   = ON;
            s_uds_can_comm_ctrl.nwm_send_flag  = ON;
        }
        else if(MODE_28_SUB_COMM_ENABLE_RX_DISABLE_TX == cmd)
        {
            s_uds_can_comm_ctrl.nwm_rec_flag   = ON;
            s_uds_can_comm_ctrl.nwm_send_flag  = OFF;
        }
        else if(MODE_28_SUB_COMM_ENABLE_TX_DISABLE_RX == cmd)
        {
            s_uds_can_comm_ctrl.nwm_rec_flag   = OFF;
            s_uds_can_comm_ctrl.nwm_send_flag  = ON;
        }
        else if(MODE_28_SUB_COMM_DISABLE_RX_TX == cmd)
        {
            s_uds_can_comm_ctrl.nwm_rec_flag   = OFF;
            s_uds_can_comm_ctrl.nwm_send_flag  = OFF;
        }
        else
        {
            /* do nothing */
        }
    }
    else if(MODE_28_CTRL_TYPE_APP_AND_NWM == type)
    {
        if(MODE_28_SUB_COMM_ENABLE_RX_TX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = ON;
            s_uds_can_comm_ctrl.app_send_flag  = ON;
            s_uds_can_comm_ctrl.nwm_rec_flag   = ON;
            s_uds_can_comm_ctrl.nwm_send_flag  = ON;
        }
        else if(MODE_28_SUB_COMM_ENABLE_RX_DISABLE_TX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = ON;
            s_uds_can_comm_ctrl.app_send_flag  = OFF;
            s_uds_can_comm_ctrl.nwm_rec_flag   = ON;
            s_uds_can_comm_ctrl.nwm_send_flag  = OFF;
        }
        else if(MODE_28_SUB_COMM_ENABLE_TX_DISABLE_RX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = OFF;
            s_uds_can_comm_ctrl.app_send_flag  = ON;
            s_uds_can_comm_ctrl.nwm_rec_flag   = OFF;
            s_uds_can_comm_ctrl.nwm_send_flag  = ON;
        }
        else if(MODE_28_SUB_COMM_DISABLE_RX_TX == cmd)
        {
            s_uds_can_comm_ctrl.app_rec_flag   = OFF;
            s_uds_can_comm_ctrl.app_send_flag  = OFF;
            s_uds_can_comm_ctrl.nwm_rec_flag   = OFF;
            s_uds_can_comm_ctrl.nwm_send_flag  = OFF;
        }
        else
        {
            /* do nothing */
        }
    }
    else
    {
        /* do nothing */
    }
    UdsCallBack_CommCtrl(COMM_APP_REC,  s_uds_can_comm_ctrl.app_rec_flag);
    UdsCallBack_CommCtrl(COMM_APP_SEND, s_uds_can_comm_ctrl.app_send_flag);
    UdsCallBack_CommCtrl(COMM_NWM_REC,  s_uds_can_comm_ctrl.nwm_rec_flag);
    UdsCallBack_CommCtrl(COMM_NWM_SEND, s_uds_can_comm_ctrl.nwm_send_flag);
}

/****************************************************************************/
/**
 * Function Name: udsAppl_GetCommCtrlFlag
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/08, hui.pang create this function
 ****************************************************************************/
BOOL udsAppl_GetCommCtrlFlag(Uds_CanCommCtrlSts_E flag)
{
    if(COMM_APP_SEND == flag)
    {
        return s_uds_can_comm_ctrl.app_send_flag;
    }
    else if(COMM_APP_REC == flag)
    {
        return s_uds_can_comm_ctrl.app_rec_flag;
    }
    else if(COMM_NWM_SEND == flag)
    {
        return s_uds_can_comm_ctrl.nwm_send_flag;
    }
    else if(COMM_NWM_REC == flag)
    {
        return s_uds_can_comm_ctrl.nwm_rec_flag;
    }
    else
    {
        return FALSE;
    }
}

#endif  /* MODE_28_SUPPORTED */

#ifdef MODE_2E_SUPPORTED

/****************************************************************************/
/**
 * Function Name: UdsAppl_WriteE2ByPara
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/29, hui.pang create this function
 ****************************************************************************/
void UdsAppl_WriteE2ByPara(UINT16 add, UINT8 len, UINT8 * pData)
{
    s_u16_addr_e2 = add;
    s_u8_bytes_e2 = len;
	(void)memset(s_u32_buffer_e2, 0x00, sizeof(s_u32_buffer_e2)); /* clear buffer before write it */
    (void)memcpy(s_u32_buffer_e2, pData, len);
    s_b_write_e2_flag = SET;
    e_pendingType = UDS_Pending_Write_E2;
    s_fsm_pending_sts = FSM_UDS_Pending_Idle;
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_DiagWriteDataByIdentifier_0x2E
 * Description: This function processes incoming requests
 *              (0x2E)write data by identifier
 *
 * Param:   none
 * Return:  none
 * Author:  2014/11/25, hui.pang create this function
 ****************************************************************************/
void UdsAppl_DiagWriteDataByIdentifier_0x2E(void)
{
    const Uds_DidWriteRecord_S * did_table_ptr;
    UINT16 u16_did = 0;
    UINT8 response = FALSE;

    /////////////////////////////////////////////////////////
    if(FALSE == UdsAppl_CheckService(WRBYID, TRUE))
    {
        return;
    }

    if(UdsDiag_WriteDataCondition() == FALSE)
    {
        DiagExConditionsNotCorrect_Nrc22();
        return ;
    }

    did_table_ptr = diag_did_write_table_rom;

    u16_did = MERGE_U8_TO_U16(DiagBuffer[_DATA1],
                              DiagBuffer[_DATA2]);

    while(did_table_ptr->did != 0)
    {
        if(did_table_ptr->did == u16_did)
        {
            /* Check to see if data bytes requirements are met */
            if(DiagDataLength != (did_table_ptr->length + 3))
            {
                /* 0x13, Not the correct number of data bytes, so respond with INVALID */
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }

            if(FALSE == UdsAppl_CheckAccessLevels(did_table_ptr->access_mode))
            {
                DiagExsecurityAccessDenied_Nrc33();
                return ;
            }

            response = did_table_ptr->did_write_function_ptr(&DiagBuffer[_DATA3],
                       did_table_ptr->length);
            /*
            ** check the response code
            */
            if(response == TRUE)
            {
                if(s_b_write_e2_flag == SET)
                {
                    /* pending, wait for write2e, so don't send any response here */
                }
                else
                {
                    UdsInterface_PutResponse(FALSE, 3);
                }
            }
            else /* write data by identifier error */
            {
                DiagExConditionsNotCorrect_Nrc22();
            }
            return;
        }
        ++did_table_ptr;
    }

    /* 0x31 - the DID is not supported in the server */
    DiagExRequestOutofRange_Nrc31();
    return;
}
#endif  /* MODE_2E_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagInputOutputCtrlByIdentifier_0x2F(void)
* Description:  This function processes incoming requests
                (0x2F)input output ctrl by identifier
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_2F_SUPPORTED

void UdsAppl_DiagInputOutputCtrlByIdentifier_0x2F(void)
{
    UINT16 u16_req_pid;
    Uds_IOCtrlRecord_S const *ioctl_record_ptr;
    UINT8 ioctrl_cmd;
    UINT8 *ioctrl_parameter;
    UINT8 ioctrl_result;

    if(FALSE == UdsAppl_CheckService(IOCTRLBYID, TRUE))
    {
        return;
    }

    if(UdsDiag_InputOutputControlCondition() == FALSE)
    {
        DiagExConditionsNotCorrect_Nrc22();
        return ;
    }

    u16_req_pid = MERGE_U8_TO_U16(DiagBuffer[_DATA1],
                                  DiagBuffer[_DATA2]);

    ioctrl_cmd = DiagBuffer[_DATA3];
    ioctrl_parameter = &DiagBuffer[_DATA4];

    ioctl_record_ptr = &diag_ioctl_table_rom[0];

    ///////////////////////////////////////////////////

    while(ioctl_record_ptr->local_id != 0x0000)
    {
        if(ioctl_record_ptr->local_id == u16_req_pid)
        {
            if(FALSE == UdsAppl_CheckAccessLevels(ioctl_record_ptr->access_mode))
            {
                DiagExsecurityAccessDenied_Nrc33();
                return ;
            }

            if(((ioctrl_cmd == IO_CTRL_CMD_SHORT_TERM_ADJUSTMENT) && (DiagDataLength != ioctl_record_ptr->data_length + 4))
                || ((ioctrl_cmd != IO_CTRL_CMD_SHORT_TERM_ADJUSTMENT) && (DiagDataLength != 4)))
            {
                /* 0x13,incorrectMessageLengthOrInvalidFormat,the length of the message is wrong. */
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return;
            }

            if((ioctrl_cmd == IO_CTRL_CMD_RETURN_TO_ECU && c_b_0x2F_cmd_return_to_ecu_cmd_enable)
                || (ioctrl_cmd == IO_CTRL_CMD_RESET_TO_DEFAULT && c_b_0x2F_cmd_reset_to_default_cmd_enable)
                || (ioctrl_cmd == IO_CTRL_CMD_FREEZE_CURRENT_STATE && c_b_0x2F_cmd_freeze_current_state_cmd_enable)
                || (ioctrl_cmd == IO_CTRL_CMD_SHORT_TERM_ADJUSTMENT && c_b_0x2F_cmd_short_term_adjustment_enable)
                )
            {
                ioctrl_result = ioctl_record_ptr->fun(ioctrl_cmd, ioctrl_parameter);
            }
            else
            {
                DiagExRequestOutofRange_Nrc31();
                return;
            }

            if(ioctrl_result == TRUE)
            {
                UdsInterface_PutResponse(FALSE, 0);
            }
            else
            {
                DiagExConditionsNotCorrect_Nrc22();
            }

            return;
        }
        ++ioctl_record_ptr;
    }
    /*
    ** 0x31,requestOutOfRange
    ** This code shall be returned if:
    ** 1) The requested dataIdentifier value is not supported by ECU;
    ** 2) The dataIdentifier uses the controlState parameter as an
    ** inputOutputControlParameter and the value contained in this parameter is invalid;
    ** 3) One or more of the applicable controlStates of the controlOptionRecord are invalid.
    */
    DiagExRequestOutofRange_Nrc31();
    return;
}

#endif  /* MODE_2F_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagRoutineCtrlByIdentifier_0x31(void)
* Description:  This function processes incoming requests
                (0x31) routine ctrl by localidentifier
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_31_SUPPORTED

#define set_routiue_in_progress(index) \
    ( routinue_running_state_array[ (index & 0x00FF )/ (UINT8) 8 ] |= (UINT8)((UINT8) 1 << ((UINT8)((index) & 7))) )

#define clear_routiue_in_progress(index) \
    ( routinue_running_state_array[ (index & 0x00FF )/ (UINT8) 8 ] &= \
            (UINT8)(~(UINT8)((UINT8) 1 << ((UINT8)((index) & 7)))) )

#define is_routiue_in_progress(index) \
    ((UINT8)( routinue_running_state_array[ (index & 0x00FF )/ (UINT8) 8 ] & \
              (UINT8)((UINT8) 1 << ((UINT8)((index) & 7))) ))

void UdsAppl_DiagRoutineCtrlByIdentifier_0x31(void)
{
    static UINT8 routineStatusByte[MODE31_STATUS_BYTE_LENGTH];
    Uds_RoutineCtrlRecord_S const *routinectl_record_ptr;
    RoutineCtrl_Cmd_E routine_cmd;
    UINT16 u16_routine_id = 0;
    UINT8 u8_option_record_length;
    UINT8 u8_status_byte_length;
    UINT8 result = FALSE;


    if(FALSE == UdsAppl_CheckService(ROUTINECTRL, TRUE))
    {
        return;
    }

    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x31SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }

    routine_cmd = DiagBuffer[_DATA1];

    if(UdsDiag_RoutineControlCondition() == FALSE)
    {
        DiagExConditionsNotCorrect_Nrc22();
        return ;
    }

    routinectl_record_ptr = &diag_routine_ctrl_table_rom[0];

    u16_routine_id = MERGE_U8_TO_U16(DiagBuffer[_DATA2],
                                     DiagBuffer[_DATA3]);

    (void)memset(routineStatusByte, 0x00, sizeof(routineStatusByte));

    /////////////////////////////////////////////////

    while(routinectl_record_ptr->routine_id != 0)
    {
        if(routinectl_record_ptr->routine_id == u16_routine_id)
        {
            /* we already pass the sec access, do not need to check again */
            if(routinectl_record_ptr->fun == NULL_PTR)
            {
                DiagExConditionsNotCorrect_Nrc22();
                return;
            }

            if(START_ROUTINE == routine_cmd)
            {
                u8_option_record_length = routinectl_record_ptr->start_lenght >> 4;
                u8_status_byte_length = routinectl_record_ptr->start_lenght & 0x0F;
                
                if(DiagDataLength != u8_option_record_length + 4)
                {
                    DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                    return ;
                }
                if(SN == routinectl_record_ptr->start_access_mode)
                {
                    DiagExSubFunctionNotSupportedOrInvalidFormat_Nrc12();
                    return ;
                }
                if(FALSE == UdsAppl_CheckAccessLevels(routinectl_record_ptr->start_access_mode))
                {
                    DiagExsecurityAccessDenied_Nrc33();
                    return ;
                }
                if(FALSE == UdsDiag_RoutineDidControlCondition(START_ROUTINE, routinectl_record_ptr->index))
                {
                    DiagExServiceNotSupported_Nrc11();
                    return ;
                }

                result = (routinectl_record_ptr->fun)(START_ROUTINE,
                                                      (UINT8 const *)&DiagBuffer[_DATA4],
                                                      routineStatusByte);
                if(result == TRUE)      /* set routine progress flag when routine is  ok */
                {
                    set_routiue_in_progress(routinectl_record_ptr->index);
                }
                else                    /* clear routine progress flag when routine is not ok */
                {
                    clear_routiue_in_progress(routinectl_record_ptr->index);
                }
            }
            else if(STOP_ROUTINE == routine_cmd)
            {
                u8_option_record_length = routinectl_record_ptr->stop_lenght >> 4;
                u8_status_byte_length = routinectl_record_ptr->stop_lenght & 0x0F;

                if(DiagDataLength != u8_option_record_length + 4)
                {
                    DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                    return ;
                }

                if(SN == routinectl_record_ptr->stop_access_mode)
                {
                    DiagExSubFunctionNotSupportedOrInvalidFormat_Nrc12();
                    return ;
                }
                if(FALSE == UdsAppl_CheckAccessLevels(routinectl_record_ptr->stop_access_mode))
                {
                    DiagExsecurityAccessDenied_Nrc33();
                    return ;
                }

                if(is_routiue_in_progress(routinectl_record_ptr->index))
                {
                    if(FALSE == UdsDiag_RoutineDidControlCondition(STOP_ROUTINE, routinectl_record_ptr->index))
                    {
                        DiagExServiceNotSupported_Nrc11();
                        return ;
                    }
                    
                    result = (routinectl_record_ptr->fun)(STOP_ROUTINE,
                                                          (UINT8 const *)&DiagBuffer[_DATA4],
                                                          routineStatusByte);
                }
                else
                {
                    DiagExRequestSequenceError_Nrc24();
                    return ;
                }
            }
            else if(REQ_ROUTINE_RESULTS == routine_cmd)
            {
                u8_option_record_length = routinectl_record_ptr->result_lenght >> 4;
                u8_status_byte_length = routinectl_record_ptr->result_lenght & 0x0F;

                if(DiagDataLength != u8_option_record_length + 4)
                {
                    DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                    return ;
                }
                if(SN == routinectl_record_ptr->result_access_mode)
                {
                    DiagExSubFunctionNotSupportedOrInvalidFormat_Nrc12();
                    return ;
                }
                if(FALSE == UdsAppl_CheckAccessLevels(routinectl_record_ptr->result_access_mode))
                {
                    DiagExsecurityAccessDenied_Nrc33();
                    return ;
                }

                if(is_routiue_in_progress(routinectl_record_ptr->index))
                {
                    if(FALSE == UdsDiag_RoutineDidControlCondition(REQ_ROUTINE_RESULTS, routinectl_record_ptr->index))
                    {
                        DiagExServiceNotSupported_Nrc11();
                        return ;
                    }
                    
                    result = (routinectl_record_ptr->fun)(REQ_ROUTINE_RESULTS,
                                                          (UINT8 const *)&DiagBuffer[_DATA4],
                                                          routineStatusByte);
                }
                else
                {
                    DiagExRequestSequenceError_Nrc24();
                    return ;
                }
            }
            else
            {
                /* do nothing */
            }

            if(result == TRUE)
            {
                if(u8_status_byte_length != 0)
                {
                    (void)memcpy(&DiagBuffer[_DATA4], routineStatusByte, u8_status_byte_length);
                }

                UdsInterface_PutResponse(FALSE, 4 + u8_status_byte_length);
            }
            else if(REQ_ROUTINE_RESULTS == routine_cmd)     /* pending */
            {
                e_pendingType = UDS_Pending_Start_Routine;
                p_s_routinePanding = routinectl_record_ptr;
                b_routinePandingFlag = SET;
                return;
            }
            else
            {
                DiagExConditionsNotCorrect_Nrc22();
            }
            return ;
        }
        ++routinectl_record_ptr;
    }
    
    if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
    {
        /* 0x31 - "group Of DTC" is wrong.Only 0xFFFFFF(all groups) is supported. */
        DiagExRequestOutofRange_Nrc31();
    }
    else
    {
        UdsInterface_QuitWithoutSendNegativeResponse();
    }
}
#endif  /* MODE_31_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagTesterPresent_0x3E(void)
* Description:   This function processes incoming requests
                (0x3E) tester present service
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_3E_SUPPORTED

void UdsAppl_DiagTesterPresent_0x3E(void)
{
    BOOL b_forbid_flag = FALSE;

    //////////////////////////////////////

    if(FALSE == UdsAppl_CheckService(TSTRPRNT, TRUE))
    {
        return;
    }
    
    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x3ESubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }

    b_forbid_flag = DIAG_CHECK_FORBID_BIT(); /* Check Forbid */

    /* clear timerout timer */
    s_u16_test_present_time_out_cnt = TIMEOUT_5_SECONDS;
    
    /* RQ, 20131028, should not response */
    /* RQ, 20120730, 0XFF means we do not need to send back any msg,
       only used to clear some flag */
    UdsInterface_PutResponse(b_forbid_flag, 0);
}
#endif /* MODE_3E_SUPPORTED */

/*****************************************************************************/
/**
* Function Name: void UdsAppl_DiagDTCSettingCtrl_0x85(void)
* Description:  This function processes incoming requests
                (0x85) DTC setting control
*
* Param:   none
* Return:  none
* Author:
******************************************************************************/
#ifdef MODE_85_SUPPORTED

typedef enum /* Don't change these value */
{
    MODE_85_SUB_DTC_SETTING_ON   = 0x01,
    MODE_85_SUB_DTC_SETTING_OFF  = 0x02,

} MODE_85_SubFun_E;

void UdsAppl_DiagDTCSettingCtrl_0x85(void)
{
    BOOL b_forbid_flag = FALSE;

    /////////////////////////////////////////////

    if(FALSE == UdsAppl_CheckService(DTCSETTINGCTRL, TRUE))
    {
        return;
    }
    
    /* check special sub functions only available at certain session */
    if (FALSE == UdsAppl_CheckSubFunction(c_s_uds0x85SubFunctionConfig, DiagBuffer[ _DATA1 ], TRUE))
    {
        return;
    }

    b_forbid_flag = DIAG_CHECK_FORBID_BIT(); /* Check Forbid */

    DiagBuffer[_DATA1] &= 0x7F;

    /* set control flag */
    if(DiagBuffer[_DATA1] == MODE_85_SUB_DTC_SETTING_OFF)
    {
        UdsCallBack_StartStopDiag(OFF);
    }
    else
    {
        UdsCallBack_StartStopDiag(ON);
    }

    UdsInterface_PutResponse(b_forbid_flag, 0);
}
#endif  /* MODE_85_SUPPORTED */

/****************************************************************************/
/**
 * Function Name: UdsAppl_DiagReadMemoryByAddress_0x23
 * Description: This function processes incoming requests
                (0x23) Read Memory By Address
 *
 * Param:   none
 * Return:  none
 * Author:  2016/09/11, hui.liu create this function
 ****************************************************************************/
#ifdef MODE_23_SUPPORTED

void UdsAppl_DiagReadMemoryByAddress_0x23(void)
{
    UINT32 u32_read_memory_address = 0;
    UINT32 u32_read_memory_length = 0;
    UINT8 u8_address_bytes;
    UINT8 u8_lengh_bytes;

    if(FALSE == UdsAppl_CheckService(RDMBYADDR, TRUE))
    {
        return;
    }
    
    if(FALSE == UdsAppl_CheckAccessLevels(c_b_0x23_sec_levels))
    {
        DiagExsecurityAccessDenied_Nrc33();
        return ;
    }
    
    u8_address_bytes = DiagBuffer[_DATA1] & 0x0F;
    u8_lengh_bytes = DiagBuffer[_DATA1] >> 4;

    if(u8_address_bytes == 0 || u8_address_bytes > 4
        || u8_lengh_bytes == 0 || u8_lengh_bytes > 2
        )
    {
		DiagExRequestOutofRange_Nrc31();
    }
    
    if(DiagDataLength != 2 + u8_address_bytes + u8_lengh_bytes)
    {
        DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
        return;
    }

    if(u8_address_bytes == 1)
    {
        u32_read_memory_address = (UINT32)DiagBuffer[_DATA2];
    }
    else if(u8_address_bytes == 2)
    {
        u32_read_memory_address = ((UINT32)DiagBuffer[_DATA2]<<8)
                                + ((UINT32)DiagBuffer[_DATA3]<<0);
    }
    else if(u8_address_bytes == 3)
    {
        u32_read_memory_address = ((UINT32)DiagBuffer[_DATA2]<<16)
                                + ((UINT32)DiagBuffer[_DATA3]<<8)
                                + ((UINT32)DiagBuffer[_DATA4]<<0);
    }
    else if(u8_address_bytes == 4)
    {
        u32_read_memory_address = ((UINT32)DiagBuffer[_DATA2]<<24)
                                + ((UINT32)DiagBuffer[_DATA3]<<16)
                                + ((UINT32)DiagBuffer[_DATA4]<<8)
                                + ((UINT32)DiagBuffer[_DATA5]<<0);
    }
    
    if(u8_lengh_bytes == 1)
    {
        u32_read_memory_length = (UINT32)DiagBuffer[_DATA2+u8_address_bytes];
    }
    else if(u8_lengh_bytes == 2)
    {
        u32_read_memory_length = ((UINT32)DiagBuffer[_DATA2+u8_address_bytes]<<8)
                                + ((UINT32)DiagBuffer[_DATA3+u8_address_bytes]<<0);
    }

    if(u32_read_memory_length > RX_MAX_TP_BYTES-1)
    {
        u32_read_memory_length = RX_MAX_TP_BYTES-1;
    }

    if(UdsCallBack_ReadMemory(u32_read_memory_address, &DiagBuffer[_DATA1], (UINT16)u32_read_memory_length) == FALSE)
    {
        DiagExRequestOutofRange_Nrc31();
        return ;
    }

    UdsInterface_PutResponse(FALSE, (UINT16)(1+u32_read_memory_length));
}
#endif  /* MODE_23_SUPPORTED */

/****************************************************************************/
/**
 * Function Name: UdsAppl_DiagWriteMemoryByAddress_0x3D
 * Description: This function processes incoming requests
                (0x3D) Write Memory By Address
 *
 * Param:   none
 * Return:  none
 * Author:  2016/09/11, hui.liu create this function
 ****************************************************************************/
#ifdef MODE_3D_SUPPORTED

void UdsAppl_DiagWriteMemoryByAddress_0x3D(void)
{
    UINT32 u32_write_memory_address = 0;
    UINT32 u32_write_memory_length = 0;
    UINT8 u8_address_bytes;
    UINT8 u8_lengh_bytes;
    BOOL result;

    if(FALSE == UdsAppl_CheckService(RDMBYADDR, TRUE))
    {
        return;
    }
    
    if(FALSE == UdsAppl_CheckAccessLevels(c_b_0x3D_sec_levels))
    {
        DiagExsecurityAccessDenied_Nrc33();
        return ;
    }

    u8_address_bytes = DiagBuffer[_DATA1] & 0x0F;
    u8_lengh_bytes = DiagBuffer[_DATA1] >> 4;

    if(u8_address_bytes == 1)
    {
        u32_write_memory_address = (UINT32)DiagBuffer[_DATA2];
    }
    else if(u8_address_bytes == 2)
    {
        u32_write_memory_address = ((UINT32)DiagBuffer[_DATA2]<<8)
                                + ((UINT32)DiagBuffer[_DATA3]<<0);
    }
    else if(u8_address_bytes == 3)
    {
        u32_write_memory_address = ((UINT32)DiagBuffer[_DATA2]<<16)
                                + ((UINT32)DiagBuffer[_DATA3]<<8)
                                + ((UINT32)DiagBuffer[_DATA4]<<0);
    }
    else if(u8_address_bytes == 4)
    {
        u32_write_memory_address = ((UINT32)DiagBuffer[_DATA2]<<24)
                                + ((UINT32)DiagBuffer[_DATA3]<<16)
                                + ((UINT32)DiagBuffer[_DATA4]<<8)
                                + ((UINT32)DiagBuffer[_DATA5]<<0);
    }
    
    if(u8_lengh_bytes == 1)
    {
        u32_write_memory_length = (UINT32)DiagBuffer[_DATA2+u8_address_bytes];
    }
    else if(u8_lengh_bytes == 2)
    {
        u32_write_memory_length = ((UINT32)DiagBuffer[_DATA2+u8_address_bytes]<<8)
                                + ((UINT32)DiagBuffer[_DATA3+u8_address_bytes]<<0);
    }
    
    if(DiagDataLength != 2 + u8_address_bytes + u8_lengh_bytes + u32_write_memory_length)
    {
        DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
        return;
    }

    /* Check Write Data Address And Length */
    if(u8_address_bytes == 0 || u8_address_bytes > 4
        || u8_lengh_bytes == 0 || u8_lengh_bytes > 2
        )
    {
		DiagExRequestOutofRange_Nrc31();
        return;
    }

    if(TESTBIT(diag_mode_flags, DIAG_MODE))
    {
        result = UdsCallBack_WriteMemory(u32_write_memory_address,
                                        &DiagBuffer[_DATA2+u8_address_bytes+u8_lengh_bytes],
                                        (UINT16)u32_write_memory_length);
        if(result == FALSE)
        {
            DiagExGeneralProgrammingFailure_Nrc72();
            return ;
        }
        
        UdsInterface_PutResponse(FALSE, 2+u8_address_bytes+u8_lengh_bytes);
    }
}
#endif  /* MODE_3D_SUPPORTED */


/*****************************************************************************/
/**
* Function Name: BOOL UdsAppl_CheckAccessLevels( UINT8 access_level )
* Description:
*
* Param:   access_level- access mode
* Return:
* Author:
******************************************************************************/
static BOOL UdsAppl_CheckAccessLevels(UINT8 access_level)
{
    if(diag_sec_levels >= access_level)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_CheckLength
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2016/09/07, hui.liu create this function
 ****************************************************************************/
static BOOL UdsAppl_CheckLength(UINT16 u16_configLenght)
{
    if(u16_configLenght == LENGTH_NOT_SET
        || (!(u16_configLenght & LENGTH_MIN) && (DiagDataLength == u16_configLenght) )
        || ((u16_configLenght & LENGTH_MIN) && (DiagDataLength >= (u16_configLenght&0x7FFF)) ))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/****************************************************************************/
/**
 * Function Name: UdsAppl_CheckService
 * Description: check service session mode and length
 *
 * Param:   none
 * Return:  none
 * Author:  2016/08/23, hui.liu create this function
 ****************************************************************************/
static BOOL UdsAppl_CheckService(UINT8 u8_ServiceID, BOOL b_lenghtCheck)
{
    UINT8 u8_index = 0;
    UINT8 u8_currentSession;

    while(c_s_udsServiceConfig[u8_index].u8_serid != 0xFF)
    {
        /*find related service and subRoutine ID in config data*/
        if(u8_ServiceID == c_s_udsServiceConfig[u8_index].u8_serid)
        {
            /*check support session as well as addressing*/
            u8_currentSession = udsAppl_getCurrentSessionMode();
            if(!(u8_currentSession & c_s_udsServiceConfig[u8_index].u8_supportSession))
            {
                if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
                {
                    DiagExSerivcenotSupportInActiveSession_Nrc7F();
                }
                else
                {
                    UdsInterface_QuitWithoutSendNegativeResponse();
                }
                return FALSE;
            }

            /*check service length*/
            if(b_lenghtCheck && UdsAppl_CheckLength( c_s_udsServiceConfig[u8_index].u16_serlength) == FALSE)
            {
                /* 0x13, Not the correct number of data bytes, so respond with INVALID */
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return FALSE;
            }
            
            return TRUE;
        }

        u8_index++;
    }
    
    /* 0x11 - should response when get the wrong message 
              in physical mode */
    DiagExServiceNotSupported_Nrc11();

    return FALSE;
}


/****************************************************************************/
/**
 * Function Name: UdsAppl_CheckSubFunction
 * Description: check subfunction session mode and length
 *
 * Param:   none
 * Return:  none
 * Author:  2016/08/23, hui.liu create this function
 ****************************************************************************/
static BOOL UdsAppl_CheckSubFunction(const UdsSubFunction_S *s_subFun, UINT8 u8_subFunId, BOOL b_lenghtCheck)
{
    UINT8 u8_index = 0;
    UINT8 u8_currentSession;

    while(s_subFun[u8_index].u8_subid != 0xFF)
    {
        if(u8_subFunId == s_subFun[u8_index].u8_subid)
        {
            u8_currentSession = udsAppl_getCurrentSessionMode();

            if(!(u8_currentSession & s_subFun[u8_index].u8_enabledsession))
            {
                if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
                {
                    DiagExSerivcenotSupportInActiveSession_Nrc7F();
                }
                else
                {
                    UdsInterface_QuitWithoutSendNegativeResponse();
                }
                return FALSE;
            }
            
            /*check sub function length*/
            if(b_lenghtCheck && UdsAppl_CheckLength( s_subFun[u8_index].u16_sublength) == FALSE)
            {
                /* 0x13, Not the correct number of data bytes, so respond with INVALID */
                DiagExIncorrectMessagelengthOrInvalidFormat_Nrc13();
                return FALSE;
            }
            
            return TRUE;
        }

        u8_index ++;
    }
    if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
    {
        DiagExSubFunctionNotSupportedOrInvalidFormat_Nrc12();
    }
    else
    {
        UdsInterface_QuitWithoutSendNegativeResponse();
    }

    return FALSE;
}


/****************************************************************************/
/**
 * Function Name: udsAppl_getCurrentSessionMode
 * Description: get session mode
 *
 * Param:   none
 * Return:  none
 * Author:  2016/08/23, hui.liu create this function
 ****************************************************************************/
static UINT8 udsAppl_getCurrentSessionMode(void)
{
    UINT8 u8_result = 0;
    if(g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE
            && TESTBIT(diag_mode_flags, ENDOFLINE_MODE) != 0)
    {
        u8_result = EXT_PHYS;
    }
    else if(g_diag_can_address_mode != DIAG_PHYSIC_ADDR_MODE
            && TESTBIT(diag_mode_flags, ENDOFLINE_MODE) != 0)
    {
        u8_result = EXT_FUNC;
    }
    else if(g_diag_can_address_mode != DIAG_PHYSIC_ADDR_MODE
            && TESTBIT(diag_mode_flags, ENDOFLINE_MODE) == 0)
    {
        u8_result = DEF_FUNC;
    }
    else
    {
        u8_result = DEF_PHYS;
    }
    return u8_result;
}

#pragma CODE_SEG  DEFAULT


